package com.zff.rental.utils.specification;

import jakarta.persistence.criteria.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.NonNull;

import java.util.HashMap;

/**
 * @param <PathV>  表字段类型
 * @param <Params> 入参类型
 * @author HCY
 */

public abstract class BasePre<ROOT, PathV, Params> implements Specification<ROOT> {
    private final String pathName;
    private final Params[] value;

    @SafeVarargs
    public BasePre(String pathName, Params... value) {
        this.pathName = pathName;
        this.value = value;
    }

    public Path<PathV> getPath(Root<ROOT> root, HashMap<String, Join<Object, Object>> joinCache) {
        if (pathName.contains(".")) {
            String[] pathStr = pathName.split("\\.");

            Join<Object, Object> join = null;
            if (joinCache != null) {
                join = joinCache.get(pathStr[0]);
            }
            if (join == null) {
                join = root.join(pathStr[0], JoinType.LEFT);
                if (joinCache != null) {
                    joinCache.put(pathStr[0], join);
                }
            }

            return join.get(pathStr[1]);
        }
        return root.get(pathName);
    }

    @Override
    public Predicate toPredicate(@NonNull Root<ROOT> root, CriteriaQuery<?> query, @NonNull CriteriaBuilder criteriaBuilder) {
        Path<PathV> path = getPath(root, null);
        return generate(criteriaBuilder, path, value);
    }

    public Predicate toPredicateByCacheJoin(@NonNull Root<ROOT> root, CriteriaQuery<?> query, @NonNull CriteriaBuilder criteriaBuilder, HashMap<String, Join<Object, Object>> joinCache) {
        Path<PathV> path = getPath(root, joinCache);
        return generate(criteriaBuilder, path, value);
    }

    protected abstract Predicate generate(CriteriaBuilder cb, Path<PathV> path, Params[] params);
}
